﻿namespace Raven
{
    public class ProjectileRocket : RavenProjectile
    {
        //the radius of damage, once the rocket has impacted
        private Fix _blastRadius;

        //this is used to render the splash when the rocket impacts
        private Fix _currentBlastRadius;

        //If the rocket has impacted we test all bots to see if they are within the 
        //blast radius and reduce their health accordingly
        private void InflictDamageOnBotsWithinBlastRadius()
        {
            _world.GetAllBots();
            foreach (var curBot in _world.GetAllBots())
            {
                if ((Pos() - curBot.Pos()).magnitude < _blastRadius + curBot.BRadius())
                {
                    //send a message to the bot to let it know it's been hit, and who the
                    //shot came from
                    _world.Dispatcher.DispatchMsg(Constants.SEND_MSG_IMMEDIATELY,
                        _shooterID,
                        curBot.ID(),
                        MessageType.Msg_TakeThatMF,
                        _damageInflicted);
                }
            }
        }

        //tests the trajectory of the shell for an impact
        private void TestForImpact()
        {
            //if the projectile has reached the target position or it hits an entity
            //or wall it should explode/inflict damage/whatever and then mark itself
            //as dead


            //test to see if the line segment connecting the rocket's current position
            //and previous position intersects with any bots.
            RavenBot hit = GetClosestIntersectingBot(_position - _velocity, _position);

            //if hit
            if (hit != null)
            {
                _impacted = true;

                //send a message to the bot to let it know it's been hit, and who the
                //shot came from
                _world.Dispatcher.DispatchMsg(Constants.SEND_MSG_IMMEDIATELY,
                    _shooterID,
                    hit.ID(),
                    MessageType.Msg_TakeThatMF,
                    _damageInflicted);

                //test for bots within the blast radius and inflict damage
                InflictDamageOnBotsWithinBlastRadius();
            }

            //test for impact with a wall
            Fix dist = 0;
            if (WallIntersectionTests.FindClosestPointOfIntersectionWithWalls(_position - _velocity,
                _position,
                ref dist,
                ref _impactPoint,
                _world.GetMap().GetWalls()))
            {
                _impacted = true;

                //test for bots within the blast radius and inflict damage
                InflictDamageOnBotsWithinBlastRadius();

                _position = _impactPoint;

                return;
            }

            //test to see if rocket has reached target position. If so, test for
            //all bots in vicinity
            Fix tolerance = 5;
            if ((Pos() - _target).sqrMagnitude < tolerance * tolerance)
            {
                _impacted = true;

                InflictDamageOnBotsWithinBlastRadius();
            }
        }

        public override void Update()
        {
            if (!_impacted)
            {
                _velocity = MaxSpeed() * Heading();

                //make sure vehicle does not exceed maximum velocity
                _velocity.Truncate(_maxSpeed);

                //update the position
                _position += _velocity;

                TestForImpact();
            }

            else
            {
                _currentBlastRadius += Constants.Rocket_ExplosionDecayRate;

                //when the rendered blast circle becomes equal in size to the blast radius
                //the rocket can be removed from the game
                if (_currentBlastRadius > _blastRadius)
                {
                    _dead = true;
                }
            }

            base.Update();
        }

        public ProjectileRocket(RavenBot shooter, Vector2 target) : base(EntityType.Rocket, target,
            shooter.GetWorld(), shooter.ID(), shooter.Pos(), shooter.Facing(),
            Constants.Rocket_Damage, Constants.Rocket_BRadius, Constants.Rocket_MaxSpeed, Constants.Rocket_Mass,
            Constants.Rocket_MaxForce)
        {
            _currentBlastRadius = 0;
            _blastRadius = Constants.Rocket_BlastRadius;
        }

        public Fix CurrentBlastRadius()
        {
            return _currentBlastRadius;
        }
    }
}